package com.me.hippy.sdk.demo.retrofitokhoot.api

import android.util.Log
import com.alibaba.fastjson.JSON
import com.me.hippy.sdk.demo.retrofitokhoot.model.HttpResponse
import com.me.hippy.sdk.demo.retrofitokhoot.model.ServerError
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import okhttp3.OkHttpClient


class ApiClient private constructor() : BaseApiManager<ApiService>() {
    companion object {
        val instance: ApiClient = ApiClient()
    }

    override fun baseUrl(): String {
        return "http://10.110.1.50:8080/"
    }

    override fun addInterceptor(okHttpClientBuilder: OkHttpClient.Builder) {
        okHttpClientBuilder.addInterceptor { chain ->
            val request = chain.request()
            val response = chain.proceed(
                request.newBuilder()
                    .addHeader("token", token)
                    .build()
            )
//            val refreshToken = response.header("refreshToken")
//            if (!TextUtils.isEmpty(refreshToken)) {
//                ToastUtils.showLong("refreshToken:$refreshToken")
//                response.close()
//                chain.proceed(
//                    request.newBuilder()
//                        .addHeader("token", refreshToken)
//                        .build()
//                )
//            } else {
//                response
//            }
            response

        }
    }

    private var token = ""
    fun getList(token: String): Observable<HttpResponse<Any>> {
        this.token = token
        return request(apiService.getList())
    }

    private fun refreshToken(): Observable<HttpResponse<String>> {
        return apiService.refreshToken()
    }


    fun <T : HttpResponse<*>> request(
        resultVoObservable: Observable<T>
    ): Observable<T> {
        return request(false, resultVoObservable)
    }

    fun <T : HttpResponse<*>> request(
        noneSchedulers: Boolean = false,
        resultVoObservable: Observable<T>
    ): Observable<T> {
        val e = resultVoObservable
            .flatMap(Function<HttpResponse<*>, ObservableSource<T>> { httpResponse ->
                flatResponse(httpResponse)
            })
            .onErrorResumeNext(doOnErrorAndRetry(resultVoObservable))
        return if (noneSchedulers) {
            e
        } else {
            e.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
        }
    }

    /**
     * 对网络接口返回的ResultVo进行分割操作
     */
    private fun <T> flatResponse(resultVo: HttpResponse<*>): Observable<T>? {
        return Observable.create { e ->
            logE("flatResponse:${JSON.toJSONString(resultVo)}")
            if (resultVo.isSuccess()) {
                logE("判定为success")
                e.onNext(resultVo as T)
            } else {
                logE("判定为error")
                e.onError(ServerError(resultVo))
            }
            e.onComplete()
        }
    }

    private fun <T> doOnErrorAndRetry(observable: Observable<T>): Function<Throwable, ObservableSource<T>>? {
        return object : Function<Throwable, ObservableSource<T>> {
            override fun apply(throwable: Throwable?): ObservableSource<T> {
                logE("doOnErrorAndRetry-throwable:$throwable")
                if (throwable is ServerError) {
                    logE("throwable is ServerError:${throwable.httpResponse.code}")
                    if (throwable.httpResponse.code == 200) {
                        return refreshToken()
                            .subscribeOn(Schedulers.io())
                            .flatMap { httpResponse ->
                                token = httpResponse.data
                                logE("成功获取到token：$token")
                                observable
                            }
                    }
                }
                return Observable.error(throwable)
            }
        }
    }

    private fun logE(any: Any) {
        Log.e("ApiClient========", "$any")
    }
}